﻿#include "ctabledelegate.h"
#include "imodel.h"
#include "ctablemodel.h"

#include <QVariant>
#include <QLineEdit>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QPainter>
#include <QDialog>

#include <shlib/quc_sdk/customwidget/uicustomdialog.h>
#include <shlib/quc_sdk/iconhelper/icon_helper.h>
#include "ctableeditplugin.h"

#include <ElaComboBox.h>
#include <ElaSpinBox.h>
/**
 * @class CTableDelegate
 * @brief 自定义表格代理，用于处理表格单元格的显示和编辑。
 * 继承自QStyledItemDelegate，提供了创建编辑器、设置编辑器数据、
 * 设置模型数据和更新编辑器几何形状等功能。
 */

/**
 * 构造函数
 * @param parent 父对象，通常是拥有此代理的视图。
 */
CTableDelegate::CTableDelegate(QObject *parent):QStyledItemDelegate(parent)
{

}

/**
 * 创建编辑器
 * 根据模型索引指示的数据类型创建并返回合适的编辑器小部件。
 * @param parent 父小部件。
 * @param option 样式选项，提供了关于视图项的视觉表现信息。
 * @param index 模型索引，指向要编辑的数据。
 * @return 返回创建的编辑器小部件指针，无特定值时返回nullptr。
 */
QWidget *CTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    auto userData = index.data(Qt::UserRole);
    auto data = qvariant_cast<QSharedPointer<IModel>>(userData);
    if(!data)
        return nullptr;
    if(!data->isFieldEditable(data->getFieldNameByCol(index.column())))
        return nullptr;

    if(data->fieldEnPluginEdit(data->getFieldNameByCol(index.column()))) {
        QLabel *label = new QLabel(parent);
        label->setStyleSheet("background-color: rgba(0, 0, 0, 0);");
        label->setFrameShape(QLabel::NoFrame);
        return label;
    }

    // 判断字段是否有值描述，如果有，则创建并返回下拉框编辑器
    {
        QMap<int, QString> valuesDesMap;
        if(hasValusDes(index,valuesDesMap))
        {
            auto comboBox = new ElaComboBox(parent);
            auto it = valuesDesMap.begin();
            for(;it!=valuesDesMap.end();++it)
            {
                comboBox->addItem(it.value(),it.key());
            }
            return comboBox;
        }
    }

    // 根据数据类型创建其他类型的编辑器
    auto valueVariant = index.data(Qt::DisplayRole);
    switch(valueVariant.type())
    {
    case QVariant::Int:
    case QVariant::UInt:
    {
        auto spinBox = new ElaSpinBox(parent);
        spinBox->setRange(0,std::numeric_limits<int>::max());
        return spinBox;
    }
    case QVariant::String:
    {
        auto lineEdit = new QLineEdit(parent);
        return lineEdit;
    }
    case QVariant::Double:
    {
        auto doubleSpinBox = new QDoubleSpinBox(parent);
        doubleSpinBox->setRange(0,std::numeric_limits<float>::max());
        return doubleSpinBox;
    }
    default:
        return nullptr;
    }
}

/**
 * 设置编辑器数据
 * 将模型索引指示的数据设置到指定的编辑器中。
 * @param editor 编辑器小部件。
 * @param index 模型索引，指向要编辑的数据。
 */
void CTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    auto userData = index.data(Qt::UserRole);
    auto data = qvariant_cast<QSharedPointer<IModel>>(userData);
    if(!data)
        return ;
    if(!data->isFieldEditable(data->getFieldNameByCol(index.column())))
        return ;

    if(data->fieldEnPluginEdit(data->getFieldNameByCol(index.column()))) {
        QString puginName = data->fieldPluginName(data->getFieldNameByCol(index.column()));
        if(puginName.isEmpty())
            return;

        CTableEditPlugin* pluginWindow = createPlugin(puginName);
        if(pluginWindow == nullptr)
            return;

        QString curValue = data->getFieldValueByFielddName(data->getFieldNameByCol(index.column())).toString();
        if(!pluginWindow->parseData(curValue))
            return;

        UiCustomDialog* dialog = new UiCustomDialog;
        dialog->setWindowTitle(pluginWindow->windowTitle());
        dialog->resize(400,400);
        dialog->setConten(pluginWindow);
        while (dialog->exec() == UiCustomDialog::Accepted) {

            break;
        }
        pluginWindow->deleteLater();
        dialog->deleteLater();
        return;
    }

    // 判断字段是否有值描述，如果有，则设置下拉框的当前文本
    {
         QMap<int, QString> valuesDesMap;
        if(hasValusDes(index,valuesDesMap))
        {
            auto comboBox = dynamic_cast<ElaComboBox*>(editor);
            if(comboBox)
            {
                if(!data)
                    return;
                auto value = data->getFieldValueByFielddName(data->getFieldNameByCol(index.column())).toInt();
                if(valuesDesMap.contains(value))
                {
                    auto des = valuesDesMap[value];
                    comboBox->setCurrentText(des);
                    return;
                }
            }
        }
    }

    // 根据数据类型设置其他类型编辑器的数据
    auto valueVariant = index.data(Qt::DisplayRole);
    switch(valueVariant.type())
    {
        case QVariant::Int:
        case QVariant::UInt:
        {
            auto spinBox = dynamic_cast<ElaSpinBox*>(editor);
            if(!spinBox)
                return;
            spinBox->setValue(valueVariant.toInt());
            break;
        }
        case QVariant::String:
        {
            auto lineEdit = dynamic_cast<QLineEdit*>(editor);
            if(!lineEdit)
                return;
            lineEdit->setText(valueVariant.toString());
            break;
        }
        case QVariant::Double:
        case 38:
        {
            auto doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(editor);
            if(!doubleSpinBox)
                return;
            doubleSpinBox->setValue(valueVariant.toDouble());
            break;
        }
        default:
        {

        }
    }
}

/**
 * 设置模型数据
 * 从指定的编辑器中获取数据，并将其设置到模型中。
 * @param editor 编辑器小部件。
 * @param model 模型。
 * @param index 模型索引，指向要编辑的数据。
 */
void CTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    auto userData = index.data(Qt::UserRole);//QVariant类型数据
    auto data = qvariant_cast<QSharedPointer<IModel>>(userData);//转IModel
    if(!data)
        return;
    auto col = index.column();//列数
    auto fieldName = data->getFieldNameByCol(col);//字段名称
    bool bUpdate = false;//标志位：数据变化
    QVariant newValue;  //新值

    if(data->fieldEnPluginEdit(data->getFieldNameByCol(index.column()))){
        return;
    }

    // 判断字段是否有值描述，如果有，则根据下拉框的当前数据更新模型
    QMap<int, QString> valuesDesMap;
    if(hasValusDes(index,valuesDesMap))
    {
        auto comboBox = dynamic_cast<ElaComboBox*>(editor);
        if(comboBox)
        {
            newValue = comboBox->currentData();
            if(newValue != data->getFieldValueByFielddName(fieldName))
            {
                bUpdate = true;
            }
        }
    }
    else{
        // 根据编辑器类型将数据设置到模型中
        auto displayData = index.data(Qt::DisplayRole);
        switch(displayData.type())
        {
            case QVariant::Int:
            case QVariant::UInt:
            {
                auto spinBox = dynamic_cast<ElaSpinBox*>(editor);
                newValue = spinBox->value();
                if(newValue != data->getFieldValueByFielddName(fieldName)){
                    bUpdate = true;
                }
                break;
            }
            case QVariant::String:
            {
                auto lineEdit = dynamic_cast<QLineEdit*>(editor);
                newValue = lineEdit->text();
                if(newValue != data->getFieldValueByFielddName(fieldName)){
                    bUpdate = true;
                }
                break;
            }
            case QVariant::Double:
            case 38:
            {
                auto doubleSpinBox = dynamic_cast<QDoubleSpinBox*>(editor);
                newValue = doubleSpinBox->value();
                if(newValue != data->getFieldValueByFielddName(fieldName)){
                    bUpdate = true;
                }
                break;
            }
            default:
            {
                return;
            }
        }
    }

    //调用model的setData函数
    if(bUpdate)
        model->setData(index,newValue,Qt::UserRole);
}

/**
 * 更新编辑器几何形状
 * 根据视图项的矩形区域设置编辑器的大小和位置。
 * @param editor 编辑器小部件。
 * @param option 样式选项，提供了关于视图项的视觉表现信息。
 * @param index 模型索引，指向要编辑的数据。
 */
void CTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry(option.rect);
}

/**
 * 编辑器事件处理
 * 处理与编辑器相关的事件。
 * @param event 事件对象。
 * @param model 模型。
 * @param option 样式选项，提供了关于视图项的视觉表现信息。
 * @param index 模型索引，指向要编辑的数据。
 * @return 返回事件是否被处理。
 */
bool CTableDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{

    return QStyledItemDelegate::editorEvent(event,model,option,index);
}

void CTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    auto value = index.data(Qt::UserRole); // 从指定索引处获取数据，使用Qt::UserRole作为数据角色
    auto data = qvariant_cast<QSharedPointer<IModel>>(value); // 将获取到的数据转换为IModel类型的智能指针

    QString fieldName = data->getFieldNameByCol(index.column());

    if(data->fieldIsEnBg(fieldName)) {
        QString colorbuf = data->fieldBg(fieldName);
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(QColor(colorbuf));
        painter->drawRect(option.rect);
        painter->restore();
    }

    if(data->fieldEnPluginEdit(fieldName)) {
        painter->save();

        QBrush brush(QColor(179, 224.5, 156.5));
        painter->setPen(Qt::NoPen);
        painter->setBrush(brush);

        int iconwidth = option.rect.height()-8;
        int btnwidth = 100;
        int braoud = 5;

        if(!(option.state & QStyle::State_MouseOver)) {
            QRectF boxrect = QRectF(option.rect.x() + (option.rect.width()-btnwidth)/2, option.rect.y()+(option.rect.height() - iconwidth)/2, btnwidth, iconwidth);
            painter->drawRoundedRect(boxrect, braoud, braoud);
        } else {
            painter->drawRect(option.rect);
        }
        painter->restore();

        IconHelper* iconMgr = IconHelper::instance();
        QPixmap pix = iconMgr->getPixmap(QColor::fromString("#E6A23C"),IconHelper::FontAwesome6Solid , 0xf044,option.rect.height()-12 , option.rect.height()-8, option.rect.height()-8);
        painter->drawPixmap(option.rect.x() + 5 + (option.rect.width()-btnwidth)/2, option.rect.y()+(option.rect.height() - iconwidth)/2, iconwidth, iconwidth, pix);

        painter->save();
        painter->setPen(Qt::black);
        QString text("编辑详情");
        painter->drawText(option.rect.x() + (option.rect.width()-btnwidth)/2 + 10 + iconwidth, option.rect.y()+(option.rect.height() - iconwidth)/2+iconwidth-5, text);
        painter->restore();
    } else {
        QStyledItemDelegate::paint(painter,option,index);
    }

    if(option.state & QStyle::State_Selected)
    {
        // 检查数据是否非空且对应字段是否可编辑，如果是，则设置相应的标志
        if(data && data->isFieldEditable(data->getFieldNameByCol(index.column())))
        {
            int x = option.rect.x();
            int y = option.rect.y();
            int width = option.rect.width();
            int height = option.rect.height();
            QRect editableRect(x+width-5-m_editableRectHeight,y+5,m_editableRectWidth,m_editableRectHeight);
            painter->setBrush(Qt::green);
            painter->setPen(Qt::NoPen);
            painter->drawEllipse(editableRect);
        }
    }
}

/**
 * 检查是否有值描述
 * 根据模型索引检查对应字段是否有值描述。
 * @param index 模型索引，指向要检查的数据。
 * @param valuesDesMap 用于存储值描述的映射。
 * @return 返回是否有值描述。
 */
bool CTableDelegate::hasValusDes(const QModelIndex &index, QMap<int, QString> &valuesDesMap) const
{
    bool bHasValueDes = false;

    // 获取存储的数据
    auto userData = index.data(Qt::UserRole);
    auto data = qvariant_cast<QSharedPointer<IModel>>(userData);
    if(!data)
        return bHasValueDes;

    // 获取字段名称
    auto fieldName = data->getFieldNameByCol(index.column());
    // 获取值描述映射
    valuesDesMap = data->getValueDesMap(fieldName,true);

    bHasValueDes = valuesDesMap.size()>0;

    return bHasValueDes;
}
